package com.esdk.utils;

import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ReflectUtil;
import com.esdk.esdk;
import com.esdk.exception.SdkRuntimeException;
import lombok.NonNull;

import java.io.Serializable;
import java.lang.reflect.*;
import java.util.*;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 扩展Apache Commons BeanUtils, 提供一些反射方面缺失功能的封装.
 */
public class EasyReflect{
	private static Map<Class,Method[]> getterMethodsPool=new LimitedHashMap<Class,Method[]>(1000);
	private static Map<String,Method> setterMethodPool=new CacheMap<String,Method>(60*60*24);
	private static Map<String,Method> getterMethodPool=new CacheMap<>(60*60*24);

	/**
	 * 循环向上转型,获取对象的DeclaredField.
	 * @throws NoSuchFieldException 如果没有该Field时抛出.
	 */
	public static Field getDeclaredField(@NonNull Object object,@NonNull String propertyName) throws NoSuchFieldException{
		return getDeclaredField(object.getClass(),propertyName);
	}

	/**
	 * 循环向上转型,获取对象的DeclaredField.
	 * @throws NoSuchFieldException 如果没有该Field时抛出.
	 */
	public static Field getDeclaredField(@NonNull Class clazz,@NonNull String propertyName) throws NoSuchFieldException{
		for(Class superClass=clazz;superClass!=Object.class;superClass=superClass.getSuperclass()){
			try{
				return superClass.getDeclaredField(propertyName);
			}
			catch(NoSuchFieldException e){
				// Field不在当前类定义,继续向上转型
			}
		}
		throw new NoSuchFieldException("No such field: "+clazz.getName()+'.'+propertyName);
	}

	public static Object getFieldValueBySafe(Object instance,@NonNull String fieldName) {
		if(instance==null)return null;
		try{
			Field field=esdk.array.filterFirst(instance.getClass().getFields(),e->e.getName().equals(fieldName));
			return field!=null?field.get(instance):null;
		}
		catch(Exception e){
			throw new RuntimeException(e);
		}
	}
	public static Object getDeclaredMethodValue(Object object,@NonNull String methodName){
		if(object==null)
			return null;
		else {
			try{
				Method m=object.getClass().getDeclaredMethod(methodName);
				m.setAccessible(true);
				return m.invoke(object,new Object[]{});
			}catch(Exception e){
				throw esdk.tool.wrapThrowble(e);
			}
		}
	}


	public static Object getMethodValue(Object object,@NonNull String methodName){
		if(object==null)
			return null;
		else {
			try{
				Method m=object.getClass().getMethod(methodName);
				m.setAccessible(true);
				return m.invoke(object,new Object[]{});
			}catch(Exception e){
				throw esdk.tool.wrapThrowble(e);
			}
		}
	}

	public static Object getFieldValue(Object instance,@NonNull String fieldName) {
		if(instance==null)return null;
		try{
			return instance.getClass().getField(fieldName).get(instance);
		}
		catch(Exception e){
			throw new RuntimeException(e);
		}
	}

	public static Object getFieldValue(Object instance,@NonNull String fieldName,boolean ignoreCase) {
		if(instance==null)
			return null;
		if(!ignoreCase)
			return getFieldValue(instance,fieldName);
		else {
			Field f=findField(instance.getClass(),fieldName,ignoreCase);
			if(f!=null){
				try{
					return f.get(instance);
				}catch(Exception e){
					throw new RuntimeException(e);
				}
			}
			return null;
		}
	}

	public static void setFieldValue(Object instance,@NonNull String fieldName,@NonNull Object fieldValue) {
		ReflectUtil.setFieldValue(instance,fieldName,fieldValue);
	}

	public static Object getFieldValue(@NonNull Object obj,@NonNull Field field){
		try{
			return field.get(obj);
		}catch(IllegalArgumentException|IllegalAccessException e){
			throw esdk.tool.wrapThrowble(e);
		}
	}

	public static Object[] getFieldValues(String[] fieldNames,Object... objs){
		if(objs==null||EasyObj.isEmpty(fieldNames))
			return null;
		ArrayList list=new ArrayList(fieldNames.length);
			try{
				for(int i=0;i<fieldNames.length;i++) {
					String fieldname=fieldNames[i];
					for(int j=0;j<objs.length;j++){
						Object obj=objs[j];
						Field field=findField(obj.getClass(),fieldname,true);
						if(field!=null) {
							list.add(field.get(obj));
							break;
						}
					}
				}
			}
			catch(IllegalArgumentException e){
				throw new RuntimeException(e);
			}
			catch(IllegalAccessException e){
				throw new RuntimeException(e);
			}
			return list.toArray();
	}

	public static ArrayList getGetMethodValues(@NonNull String propertyName,@NonNull Object... objs) {
		ArrayList result=new ArrayList(objs.length);
		for(int i=0;i<objs.length;i++) {
			result.add(getGetMethodValue(objs[i],propertyName));
		}
		return result;
	}

	public static ArrayList getGetMethodValues(@NonNull String propertyName,@NonNull List list) {
		return getGetMethodValues(propertyName,list.toArray());
	}

	/**
	 * 暴力获取对象变量值,忽略private,protected修饰符的限制.
	 * @throws NoSuchFieldException 如果没有该Field时抛出.
	 * @throws IllegalAccessException
	 * @throws IllegalArgumentException
	 */
	public static Object getDeclaredFieldValue(@NonNull Object object,@NonNull String fieldName){
		try{
			Field field=getDeclaredField(object,fieldName);
			return getDeclaredFieldValue(object,field);
		}catch(Exception e) {
			throw new RuntimeException(e);
		}
	}

	public static Object getDeclaredFieldValue(@NonNull Object object,@NonNull Field field){
		boolean accessible=field.isAccessible();
		field.setAccessible(true);
		Object result=null;
		result=getFieldValue(object,field);
		field.setAccessible(accessible);
		return result;
	}


	/**
	 * 暴力设置对象变量值,忽略private,protected修饰符的限制.
	 * @throws NoSuchFieldException 如果没有该Field时抛出.
	 * @throws IllegalAccessException
	 * @throws IllegalArgumentException
	 */
	public static void forceSetProperty(@NonNull Object object,@NonNull String fieldName,@NonNull Object newValue) throws NoSuchFieldException,IllegalArgumentException,IllegalAccessException{
		Field field=getDeclaredField(object,fieldName);
		boolean accessible=field.isAccessible();
		field.setAccessible(true);
		field.set(object,newValue);
		field.setAccessible(accessible);
	}

	/**
	 * 暴力调用对象函数,忽略private,protected修饰符的限制.
	 * @throws NoSuchMethodException 如果没有该Method时抛出.
	 * @throws InvocationTargetException
	 * @throws IllegalAccessException
	 * @throws IllegalArgumentException
	 */
	public static Object invokePrivateMethod(@NonNull Object object,@NonNull String methodName,Object...params) throws NoSuchMethodException,IllegalArgumentException,IllegalAccessException,InvocationTargetException{
		Class[] types=new Class[params.length];
		for(int i=0;i<params.length;i++){
			types[i]=params[i].getClass();
		}
		Class clazz=object.getClass();
		Method method=null;
		Class superClass=clazz;
		while(superClass!=Object.class){
			method=superClass.getDeclaredMethod(methodName,types);
			if(method!=null)
				break;
			else
				superClass=superClass.getSuperclass();
		}
		if(method==null){
			throw new NoSuchMethodException("No Such Method:"+clazz.getSimpleName()+methodName);
		}
		boolean accessible=method.isAccessible();
		method.setAccessible(true);
		Object result=method.invoke(object,params);
		method.setAccessible(accessible);
		return result;
	}

	/**
	 * 按Filed的类型取得Field列表.
	 */
	public static List<Field> getFieldsByType(@NonNull Object object,@NonNull Class type){
		List<Field> list=new ArrayList<Field>();
		Field[] fields=object.getClass().getDeclaredFields();
		for(Field field:fields){
			if(field.getType().isAssignableFrom(type)){
				list.add(field);
			}
		}
		return list;
	}

	/**
	 * 按FiledName获得Field的类型.
	 */
	public static Class getPropertyType(@NonNull Class type,@NonNull String name) throws NoSuchFieldException{
		return getDeclaredField(type,name).getType();
	}

	/**
	 * 获得field的getter函数名称.
	 */
	public static @NonNull String getGetterName(@NonNull Class type,@NonNull String fieldName){
		if(type.getName().equals("boolean")){
			return "is"+esdk.str.upperFirst(fieldName);
		}
		else{
			return "get"+esdk.str.upperFirst(fieldName);
		}
	}

	public static @NonNull String getFieldName(@NonNull Method method,boolean usePropertyName,boolean useUnderscoreName) {
		String methodname=method.getName();
		String fieldname;
		if(methodname.startsWith("get"))
			fieldname=methodname.substring(3);
		else if(methodname.startsWith("is"))
			fieldname=methodname.substring(2);
		else
			fieldname=methodname;
		if(usePropertyName)
			fieldname=esdk.str.toCamelCase(fieldname);
		else if(useUnderscoreName)
			fieldname=esdk.str.toUnderlineCase(fieldname);
		return fieldname;
	}

	/**
	 * 获得field的getter函数,如果找不到该方法,返回null.
	 * @throws NoSuchMethodException
	 * @throws SecurityException
	 */
	public static @NonNull Method getGetterMethod(@NonNull Class type,@NonNull String fieldName) throws SecurityException,NoSuchMethodException{
		return type.getMethod(getGetterName(type,fieldName));
	}
	public static @NonNull Object getGetMethodValue(@NonNull Object object,@NonNull String propertyName){
		Method m=findGetterMethod(object.getClass(),propertyName);
		try{
			return m.invoke(object,new Object[]{});
		}catch(Exception e){
			throw new SdkRuntimeException("can not find the getter method name:"+propertyName);
		}
	}

  public static Object getPropertyValue(Object object,@NonNull String propertyName){
  	if(object==null)
  		return null;
  	if(object instanceof Map)
  		return ((Map)object).get(propertyName);
  	else
  		return getGetMethodValue(object,propertyName);
  }

	public static boolean hasGetterMethod(@NonNull Class cls,@NonNull String propertyName) {
		return findGetterMethod(cls,propertyName)!=null;
	}

	public static Field findField(@NonNull Class cls,@NonNull String fieldName,boolean isIgnoreCase) {
		Field[] fields=cls.getFields();
		for(int i=0;i<fields.length;i++){
			if(isIgnoreCase&&fields[i].getName().equalsIgnoreCase(fieldName))
				return fields[i];
			else if(fields[i].getName().equals(fieldName))
				return fields[i];
		}
		return null;
	}

	public static boolean hasSetterMethod(@NonNull Class cls,@NonNull String propertyName) {
		return findSetterMethod(cls,propertyName)!=null;
	}

	public static boolean copyBeanProperty(Object from,Object to,String...excludes) {
		return copyBeanProperty(from,to,null,false,excludes);
	}

	public static boolean copyBeanProperty(Object from,Object to,Map map,String...excludes) {
		return copyBeanProperty(from,to,map,false,excludes);
	}

	public static boolean copyBeanProperty(Object from,Object to,boolean acceptNull,String...excludes) {
		return copyBeanProperty(from,to,null,acceptNull,excludes);
	}

	private static Map convertToBeanProperty(Map<String,String> map) {
		if(map==null)return map;
		HashMap result=new HashMap(map.size());
		for(Iterator iter=map.entrySet().iterator();iter.hasNext();) {
			Entry<String,String> entry=(Entry)iter.next();
			String key=EasyStr.upperFirst(entry.getKey());
			String value=EasyStr.upperFirst(entry.getValue());
			result.put(key,value);
		}
		return result;
	}

	/**默认忽略字段值为null的复制*/
	public static <T> T copyBeanProperties(Object from,T to) {
		return copyBeanProperties(from,to,false,true,null,null);
	}
	/**默认忽略字段值为null的复制*/
	public static <T> T copyBeanProperties(Object from,T to,String includesRegex) {
		return copyBeanProperties(from,to,false,true,includesRegex,null);
	}

	public static <T> T copyBeanProperties(Object from,T to,boolean acceptNull,boolean ignoreCase,String includesRegex,String excludesRegex){
		return copyBeanProperties(from,to,acceptNull,ignoreCase,null,includesRegex,excludesRegex);
	}
	/**
	 * 这个方法是最新的,推荐优先使用这个,其他类似的copyProperty方法会在以后删除.
	 * @param from
	 * @param to
	 * @param acceptNull
	 * @param includesRegex
	 * @return
	 */
	public static <T> T copyBeanProperties(Object from,T to,boolean acceptNull,boolean ignoreCase, Map propertyNameMap, String includesRegex,String excludesRegex){
		if(from==null||to==null)
			return null;
		List<Method[]> list=findMethodsInterSection(from,to,ignoreCase,propertyNameMap,includesRegex,excludesRegex);
		try{
			for(Iterator iter=list.iterator();iter.hasNext();){
				Method[] methods=(Method[])iter.next();
				Method getMethod=methods[0];
				Method setMethod=methods[1];
				Parameter[] setMethodParameters = setMethod.getParameters();
				if(setMethodParameters.length != 1) continue;
				Class setClass = setMethodParameters[0].getType();
				getMethod.setAccessible(true);
				Object getValue=getMethod.invoke(from);
				// 类型不匹配且非继承关系，直接强转
				if(!(setClass == getMethod.getReturnType() || setClass.isAssignableFrom(getMethod.getReturnType()))){
					getValue = esdk.obj.convert(getValue, setClass);
				}
				if(acceptNull||getValue!=null){
					setMethod.setAccessible(true);
					setMethod.invoke(to,getValue);
				}
			}
			return to;
		}catch(Exception e){
			throw esdk.tool.wrapThrowble(e);
		}
	}

	/**
	 * 找出getter与setter相匹配的交集
	 * */
	public static List<Method[]> findMethodsInterSection(Object from,Object to,boolean ignoreCase,Map<String,String> fromPropertyNameMap,String includesRegex,String excludesRegex) {
		if(from==null||to==null)
			return new ArrayList();
		else {
			List<Method[]> result=new LinkedList<Method[]>();
			HashMap<String,Method> fromMap=new HashMap();
			Method[] fromMethods=from.getClass().getMethods();
			for(int i=0;i<fromMethods.length;i++) {
				if(validGetMethod(fromMethods[i],includesRegex,excludesRegex)) {
					String getPropertyName=fromMethods[i].getName().replaceFirst("get|is(.*)","$1");
					fromPropertyNameMap=convertToBeanProperty(fromPropertyNameMap);
					if(fromPropertyNameMap!=null&&fromPropertyNameMap.get(getPropertyName)!=null)
						getPropertyName=fromPropertyNameMap.get(getPropertyName);
					if(ignoreCase)
						getPropertyName=getPropertyName.toUpperCase();
					fromMap.put(getPropertyName,fromMethods[i]);
				}
			}
			Method[] toMethods=to.getClass().getMethods();
			for(Method setMethod:toMethods) {
				if(setMethod.getParameterTypes().length==1&&validSetMethod(setMethod,includesRegex,excludesRegex)) {
					String setPropertyName=setMethod.getName().substring(3);
					if(ignoreCase)
						setPropertyName=setPropertyName.toUpperCase();
					Method getMethod=fromMap.get(setPropertyName);
					if(getMethod!=null)
						result.add(new Method[] {getMethod,setMethod});
				}
			}
			return result;
		}
	}

  /**TODO 需要优化性能*/
	private static boolean validGetMethod(Method method,String includesRegex,String excludesRegex) {
		String methodName=method.getName();
		String fieldName=methodName.replaceFirst("^(get|is)","");
		return !methodName.equals("setClass")
			&&method.getName().matches("(get|is).+")
			&&method.getParameterTypes().length==0
			&&(includesRegex==null||includesRegex.equals("")||includesRegex.equals("*")||fieldName.matches(includesRegex))
			&&(esdk.str.isEmpty(excludesRegex) || !fieldName.matches(excludesRegex));
	}

	private static boolean validSetMethod(Method method,String includesRegex,String excludesRegex) {
		String methodName=method.getName();
		String fieldName=methodName.replaceFirst("^set","");
		return !methodName.equals("setClass")
			&&methodName.matches("set.+")
			&&(includesRegex==null||includesRegex.equals("")||includesRegex.equals("*")||fieldName.matches(includesRegex))
			&&(esdk.str.isEmpty(excludesRegex) || !fieldName.matches(excludesRegex));
	}

	/**
	 * suggest replace with copyBeanProperties
	 * @param from
	 * @param to
	 * @param map
	 * @param acceptNull
	 * @param excludes
	 * @return
	 */
	@Deprecated
	public static boolean copyBeanProperty(Object from,Object to,Map<String,String> map,boolean acceptNull,String...excludes) {
		boolean result=false;
		if(from!=null&&to!=null&&from!=to) {
			Method[] methods=from.getClass().getMethods();
			if(excludes==null)
				excludes=new String[] {"class"};
			else
				excludes=new CharAppender(',').append(excludes).append("class").toString().split(",");
				try{
					map=convertToBeanProperty(map);
					for(int i=0;i<methods.length;i++){
						Pattern p=Pattern.compile("(get|is)(.+)",Pattern.CASE_INSENSITIVE);
						Matcher m=p.matcher(methods[i].getName());
						if(m.matches()){
							String beanPropertyName=m.group(2);
							if(map!=null&&map.get(beanPropertyName)!=null)
								beanPropertyName=map.get(beanPropertyName);
							if(!EasyStr.existOf(excludes,beanPropertyName,true)&&methods[i].getParameterTypes().length==0) {
								methods[i].setAccessible(true);
								Object getValue=methods[i].invoke(from,new Object[] {});
								if(acceptNull||getValue!=null) {
									//esdk.sout(beanPropertyName);
									Method toMethod=findSetterMethod(to.getClass(),beanPropertyName);
									if(toMethod!=null){
										toMethod.invoke(to,new Object[]{getValue});
									}
								}
							}
						}
					}
					result=true;
				}catch(IllegalArgumentException e){
					e.printStackTrace();
				}catch(IllegalAccessException e){
					e.printStackTrace();
				}catch(InvocationTargetException e){
					e.printStackTrace();
				}
		}
		return result;
	}

  public static boolean hasPropertyName(@NonNull Class cls,@NonNull String fieldName) {
		try{
	  	cls.getDeclaredField(fieldName);
	  	return true;
		}catch(SecurityException e){
			throw new RuntimeException(e);
		}catch(NoSuchFieldException e){
			return false;
		}
  }

	/**默认会触发类的初始化（执行 static 块），而 loadClass()不会！*/
	public static Class forName(@NonNull String className) {
    try{
      return Class.forName(className);
    }catch(ClassNotFoundException e){
      throw new RuntimeException(e);
    }
  }

	/**不会触发类的初始化（不执行 static 块）*/
	public static Class loadClass(@NonNull String className) {
    try{
      return Thread.currentThread().getContextClassLoader().loadClass(className);
    }catch(ClassNotFoundException e){
      throw new RuntimeException(e);
    }
  }

	private static HashMap<String,Class> _ClassMap=new HashMap();
	public static Class findClass(String... clsNames){
		Class result=null;
		for(String clsName:clsNames) {
			result=_ClassMap.get(clsName);
			if(result!=null) {
				if(!result.getClassLoader().equals(Thread.currentThread().getContextClassLoader().getParent())) {
					_ClassMap.clear();
					result=null;
				}
			}
			try{
				if(result==null) {
					result=Thread.currentThread().getContextClassLoader().loadClass(clsName);
					_ClassMap.put(clsName,result);
				}
				if(result!=null)
					break;
			}catch(ClassNotFoundException e){
				continue;
			}
		}
		return result;
	}

	public static <C> C safeNewInstance(@NonNull Class<C> clazz,Object... params){
    try{
			if(params.length==0){
				clazz.getDeclaredConstructor().setAccessible(true);
				return clazz.newInstance();
			}else{
				final Class<?>[] paramTypes = ClassUtil.getClasses(params);
				final Constructor<C> constructor = ReflectUtil.getConstructor(clazz, paramTypes);
				if (null == constructor) {
					throw new SdkRuntimeException("没有构造函数能匹配这{}个参数: [{}]", paramTypes.length,new Object[]{paramTypes});
				}
				return constructor.newInstance(params);
			}
    }catch(Exception e){
			throw esdk.tool.wrapThrowble(e);
    }
  }

	public static <C> C safeNewInstance(@NonNull String clsName){
		Class cls=forName(clsName);
		return (C)safeNewInstance(cls);
	}


	public static void setSetterMethodValue(Object obj,String propertyName,Object value){
		if(obj!=null){
			Method m=findSetterMethod(obj.getClass(),propertyName);
			if(m==null)
				throw new SdkRuntimeException("can not find the setter method name:"+propertyName);
			setSetterMethodValue(obj,m,value);
		}
	}

  public static void setSetterMethodValue(Object obj,Method m,Object value) {
  	if(obj!=null&&m!=null) {
			try{
				m.setAccessible(true);
				m.invoke(obj,new Object[]{value});
			}catch(Exception e){
				throw esdk.tool.wrapThrowble(e);
			}
  	}
  }

	/**
	 * 通过field名称找setter方法
	 * 注意：会自动把propertyName的下划线方式转为驼峰方式
	 */
	public static Method findSetterMethod(Class clazz,String propertyName) {
		propertyName=esdk.str.upperFirst(propertyName);
		String key=clazz.getName()+".set"+propertyName;
		Method result=setterMethodPool.get(key);
		if(result!=null&&!result.getDeclaringClass().getClassLoader().equals(Thread.currentThread().getContextClassLoader().getParent())) {
			setterMethodPool.clear();
			result=null;
		}
		if(!setterMethodPool.containsKey(key)) {
			Method[] methods=findSetterMethods(clazz);
			for(Method method:methods){
				if(method.getName().matches("set"+propertyName)){
					result=method;
					result.setAccessible(true);
					break;
				}
			}
			setterMethodPool.put(key,result);
		}
		return result;
	}

	/**
	 * 通过field名称找getter方法
	 * 注意：会自动把propertyName的下划线方式转为驼峰方式
	 * */
	public static Method findGetterMethod(@NonNull Class clazz,@NonNull String propertyName) {
		propertyName=esdk.str.upperFirst(propertyName);
		String key=clazz.getName()+".get"+propertyName;
		Method result=getterMethodPool.get(key);
		if(result!=null&&!result.getDeclaringClass().getClassLoader().equals(Thread.currentThread().getContextClassLoader().getParent())) {
			getterMethodPool.clear();
			result=null;
		}
		if(!getterMethodPool.containsKey(key)) {
			Method[] methods=findGetterMethods(clazz);
			for(int i=0;i<methods.length;i++){
				if(methods[i].getName().matches("(get|is)"+propertyName)) {
					result=methods[i];
					result.setAccessible(true);
					break;
				}
			}
			getterMethodPool.put(key,result);
		}
		return result;
	}


	/**
	 * 不用考虑getter的输出的顺序问题，没有性能问题，不需要缓存。
	 * */
	public static Method[] findSetterMethods(Class cls) {
		ArrayList<Method> result=new ArrayList<>();
		Method[] methods=cls.getMethods();
		for(Method method:methods){
			if(method.getName().startsWith("set")&&method.getParameterTypes().length==1) {
				result.add(method);
			}
		}
		return esdk.array.toArray(result,Method.class);
	}

	/**beanToMap*/
	public static Map toMap(@NonNull Object bean) {
		return toMap(bean,false,true,true);
	}

	public static Map toMap(@NonNull Object bean,boolean ignoreNull,boolean usePropertyName){
		return toMap(bean,ignoreNull,usePropertyName,false);
	}

	/**beanToMap
	 * @param ignoreNull: 忽略null
	 * @param usePropertyName: 强制驼峰命名key
	 * */
	public static Map toMap(@NonNull Object bean,boolean ignoreNull,boolean usePropertyName,boolean recursive){
		Method[] methods=findGetterMethods(bean.getClass());
		Map result=new LinkedHashMap(methods.length/2);
		for(int i=0;i<methods.length;i++){
			Object value=invokeMethod(bean,methods[i]);
			String key=esdk.reflect.getFieldName(methods[i],usePropertyName,false);
			if(value!=null||ignoreNull==false)
				if(!recursive || EasyBean.isPrimitive(value)||value instanceof Map || value instanceof Iterable)
					result.put(key,value);
				else
					result.put(key,toMap(value,ignoreNull,usePropertyName,true));
		}
		return result;
	}

	public static Method[] findGetterMethods(@NonNull Class clazz) {
		Method[] result=getterMethodsPool.get(clazz);
		if(result==null){
			Method[] methods=clazz.getMethods();
			EasyQuery<Method> eq=new EasyQuery();
			LinkedHashSet<Method> methodSet=new LinkedHashSet<>();
			for(Method method: methods){
				if(method.getName().matches("(get|is)[A-Z].*$")&&!method.getName().equals("getClass")&&method.getParameterTypes().length==0){
					eq.add(method);
				}
			}
			Field[] fields=esdk.array.concat(clazz.getFields(),clazz.getDeclaredFields());
			for(Field field: fields){
				Method method=eq.filterFirst(e->e.getName().matches("(get|is)"+esdk.str.upperFirst(field.getName())));
				if(method!=null){
					methodSet.add(method);
					eq.remove(method);
				}
			}
			methodSet.addAll(eq.toList());
			result=methodSet.toArray(new Method[methodSet.size()]);
			getterMethodsPool.put(clazz,result);
		}
		return result;
	}

	/**
	 * 引用链接：https://www.jianshu.com/p/85a44ee21af8
   * 根据泛型类的已经声明泛型类型的子类获取指定位置的泛型
   * @author 北北
   * @date 2018年1月18日上午11:34:59
   * @param clazz -- 当前类
   * @param index -- 第几个泛型, 从0开始
   * @return
   */
	public static <T> Class<T> getGenericClass(@NonNull Class<T> clazz,int index){
		Class<T> result=null;
		if(clazz==null)
			return null;
		// 提取泛型类数组
		Object superclass=clazz.getGenericSuperclass();
		if(superclass instanceof ParameterizedType) {
		Type[] genericTypes=((ParameterizedType)superclass).getActualTypeArguments();
		// 越界判断
		if((index+1)>genericTypes.length){
			return null;
		}
		Object obj=genericTypes[index];
		if(obj!=null && obj instanceof Class)
			result=(Class<T>)obj;
		else if(obj.getClass().getName().equals("TypeVariableImpl") || obj.toString()=="T") //即没有找到Class
			result=null;
		}
		return result;
	}

	public static Class getGenericClass(@NonNull Type type,int genericIndex){
		if(type instanceof ParameterizedType){
			Type[] genericTypes=((ParameterizedType)type).getActualTypeArguments();
			return (Class)genericTypes[genericIndex];
		}
		return null;
	}

	public static Class getGenericClass(@NonNull Method method,int parameterIndex,int genericIndex){
		Type[] genericParameterTypes=method.getGenericParameterTypes();
		if (genericParameterTypes.length > 0 && genericParameterTypes[parameterIndex] instanceof ParameterizedType) {
			ParameterizedType parameterizedType = (ParameterizedType) genericParameterTypes[parameterIndex];
			// 获取参数化类型的实际类型参数
			Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
			return (Class)actualTypeArguments[genericIndex];
		}
		return null;
	}

	private static LimitedHashMap<String,Method> _MethodMap=new LimitedHashMap(100);
	public static Method getMethod(@NonNull String fullMethodName) {
		if(_MethodMap.containsKey(fullMethodName))
			return _MethodMap.get(fullMethodName);
		else {
			try{
				int splitIndex=fullMethodName.lastIndexOf('.');
				Class cls=Class.forName(fullMethodName.substring(0,splitIndex));
				Method result=cls.getMethod(fullMethodName.substring(splitIndex+1));
				_MethodMap.put(fullMethodName,result);
				return result;
			}catch(Exception e){
				throw esdk.tool.wrapThrowble(e);
			}
		}
	}

	public static Object invokeMethod(Object instance,String fullMethodName,Object...args) {
		return invokeMethod(instance,getMethod(fullMethodName));
	}

	public static Object invokeMethod(Object instance,Method method,Object...args) {
		Object result=null;
		try{
			method.setAccessible(true);
			result=method.invoke(instance,args);
			return result;
		}catch(Exception e){
			throw esdk.tool.wrapThrowble(e);
		}
	}

	public static <T extends Serializable> T mapToBean(Map<String,Object> map,T bean) {
		return EasyBean.mapToBean(map,bean);
	}

	public static <T extends Serializable> T mapToBean(Map<String,Object> map,Class<T> clazz) {
		return EasyBean.mapToBean(map,clazz);
	}
}
